<template>
  <div>
    <p>
      学习原型，首先要理解js中JS 中构造函数和普通函数的区别：<br />
      https://blog.csdn.net/weixin_41796631/article/details/82939585
    </p>
    <el-divider></el-divider>

    <p>
      原型对象类似于java的Class对象<br />
      对象里面都有一个属性__proto__，指向原型对象。<br />
      __proto__ 不是对象属性，理解为prototype 的 getter/setter 实现，他是一个非标准定义<br />
      所以尽量避免使用__proto__，建议使用 Object.setPrototypeOf 与Object.getProttoeypOf 替代 __proto__
    </p>
    <el-divider></el-divider>

    <p>
      Function对象是特殊的对象，获取原型要用prototype。<br />
      <img src="https://doc.houdunren.com/assets/img/image-20191010012103033.3540a960.png" alt="image-20191010012103033">
    </p>
    <el-button type="primary" @click="learnFunctionPrototype">learnFunctionPrototype</el-button>
    <el-divider></el-divider>

    <p>
      设置对象的原型setPrototypeOf、获取对象的原型getPrototypeOf<br />
      Object.setPrototypeOf(要改变原型的对象，parent)<br />
    </p>
    <el-button type="primary" @click="learnSetPrototypeOf">learnSetPrototypeOf</el-button>
    <el-divider></el-divider>

    <p>
      原型检测：instanceof 、isPrototypeOf<br />
      instanceof检测
      isPrototypeOf检测一个对象是否是另一个对象的原型链中。即判断一个构造函数是不是另外一个对象的父类 <br />
    </p>
    <el-button type="primary" @click="learnInstanceof">learnInstanceof</el-button>
    <el-button type="primary" @click="learnIsPrototypeOf">learnIsPrototypeOf</el-button>
    <el-divider></el-divider>

    <p>
      属性遍历：in、hasOwnProperty<br />
      in：遍历该对象原型链上是否具有该属性
      hasOwnProperty只检测当前对象 <br />
    </p>
    <el-button type="primary" @click="learnHasOwnProperty">learnHasOwnProperty</el-button>
    <el-divider></el-divider>

    <p>
      constructor <br />
    </p>
    <el-button type="primary" @click="learnConstructor">learnConstructor</el-button>
    <el-divider></el-divider>

    <p>
      将方法定义在构造函数上会产生函数复制，导致内存占用的问题 <br />
      可以将方法定义在原型链上，优化上面的内存占用问题 <br />
    </p>
    <el-button type="primary" @click="learnConstructor">learnConstructor</el-button>
    <el-divider></el-divider>

    看到：https://doc.houdunren.com/js/11%20%E5%8E%9F%E5%9E%8B%E4%B8%8E%E7%BB%A7%E6%89%BF.html#原型链

  </div>
</template>

<script>
export default {
  methods: {
    learnFunctionPrototype () {
      function User () { }
      User.__proto__.view = function () {
        console.log("User function view method");
      };
      User.view();

      User.prototype.show = function () {
        console.log("后盾人");
      };
      let hd = new User();
      hd.show();
      // 函数对象是特殊的对象，获取原型要用prototype。
      console.log("User.prototype", User.prototype); // User.class
      // 这个获取来好像没有什么作用
      console.log("User.__proto__", User.__proto__) // { [native code] }
      console.log("hd.prototype", hd.prototype) // undefined
      console.log("hd.__proto__", hd.__proto__) // User.class
    },
    learnSetPrototypeOf () {
      let obj = { name: "后盾人", web: "web" };
      let hd = { web: "houdunren" };
      let cms = { soft: "hdcms" };
      //让obj继承hd，即设置obj的原型为hd
      Object.setPrototypeOf(obj, hd);
      Object.setPrototypeOf(hd, cms);
      console.log(obj, obj.web, obj.soft);
      console.log("Object.getPrototypeOf(hd) == cms: ", Object.getPrototypeOf(hd) == cms); //true
      console.log("Object.getPrototypeOf(obj): ", Object.getPrototypeOf(obj));
    },
    learnInstanceof () {
      function A () { }
      function B () { }
      function C () { }

      const c = new C();
      B.prototype = c;
      const b = new B();
      A.prototype = b;
      const a = new A();

      console.log(a.__proto__)
      console.dir(a instanceof A); //true
      console.dir(a instanceof B); //true
      console.dir(a instanceof C); //true
      console.dir(b instanceof C); //true
      console.dir(c instanceof B); //false
    },
    learnIsPrototypeOf () {
      const a = { a: "a" };
      const b = { b: "b" };
      const c = { c: "c" };
      // a extend b, b extend c
      Object.setPrototypeOf(a, b);
      Object.setPrototypeOf(b, c);
      console.log("a", a)
      // isPrototypeOf判断当前对象是否在another对象的原型链上，即当前对象是不是another对象的父类
      console.log(Object.prototype.isPrototypeOf.call(b, a)); //true
      console.log(Object.prototype.isPrototypeOf.call(c, a)); //true
      console.log(Object.prototype.isPrototypeOf.call(c, b)); //true
    },
    learnHasOwnProperty () {
      let a = { url: "houdunren" };
      let b = { name: "后盾人" };
      Object.setPrototypeOf(a, b);
      console.log("name" in a); // true
      console.log(Object.prototype.hasOwnProperty.call(a, "name")); // false
      console.log(Object.prototype.hasOwnProperty.call(a, "url")); // true

    },
    learnConstructor () {
      function User (name) { this.name = name; }
      console.log(User.prototype)
      User.prototype = {
        constructor: User,
        show: function () { console.log("show") }
      };
      console.log(User.prototype)
      let hd = new User("后盾人");
      let xj = new hd.constructor("向军");
      let a = xj.constructor("a");
      console.log(xj, xj.constructor, a); //String{"向军"}
    }
  }


}
</script>

<style lang="less" scoped>
p {
  line-height: 30px;
}
</style>